# from RDFDatatype import RDFDatatype
# import RDFDatatype
from base.datatypes.RDFDatatype import RDFDatatype
from base.shared.DatatypeFormatException import DatatypeFormatException
from base.shared.Objects import Objects


class BaseDatatype(RDFDatatype):
    uri = None

    def __init__(self, uri):
        self.uri = uri

    class TypedValue:
        def __init__(self, lexicalValue, datatypeURI):
            self.lexicalValue = lexicalValue
            self.datatypeURI = datatypeURI

        def __eq__(self, other):
            if isinstance(other, BaseDatatype.TypedValue):
                return self.lexicalValue == other.lexicalValue \
                    and self.datatypeURI == other.datatypeURI
            return False

        def __hash__(self):
            return hash(self.lexicalValue) ^ hash(self.datatypeURI)

    def unparse(self, value):
        if isinstance(value, BaseDatatype.TypedValue):
            return value.lexicalValue
        return value

    def parse(self, lexicalForm):
        return BaseDatatype.TypedValue(lexicalForm, self.uri)

    def isValid(self, lexicalForm):
        try:
            self.parse(lexicalForm)
            return True
        except DatatypeFormatException as err:
            print(err)
            return False

    def isValidLiteral(self, lit):
        # default is that only literals with the same type are valid
        # return self.equals(lit.getDatatype())
        return self == lit.getDatatype()

    # param LiteralLabel
    def getHashCode(self, lit):
        return lit.getDefaultHashcode()

    '''
     * Test whether the given object is a legal value form
     * of this datatype.
    '''

    def isValidValue(self, valueForm):
        # Default to brute force
        return self.isValid(self.unparse(valueForm))

    '''
     * Compares two instances of values of the given datatype.
     * This default requires value and datatype equality.
    '''

    def isEqual(self, litLabel1, litLabel2):
        return self.isEqualPlain(litLabel1, litLabel2)

    '''
     * The default for equality - same datatype, same value
    '''

    @staticmethod
    def isEqualPlain(litLabel1, litLabel2):
        return litLabel1.getDatatype() == litLabel2.getDatatype() \
            and litLabel1.getValue().equals(litLabel2.getValue())

    '''
     * Equality for datatypes based solely on lexical form,
     * i.e. there value space is equivalent to their lexical space.
    '''

    @staticmethod
    def isEqualByTerm(value1, value2):
        if value2 is None and value1 is None:
            return True
        if value2 is None:
            return False
        if value1 is None:
            return False
        return Objects.equals(value1.getLexicalForm(), value2.getLexicalForm()) and \
            Objects.equals(value1.getDatatype(), value2.getDatatype()) and \
            Objects.equals(value1.language(), value2.language())
